#ifndef COOLPOOL_SIMULATION_SIMOBJECTS_POINTMASS_H_

#define COOLPOOL_SIMULATION_SIMOBJECTS_POINTMASS_H_

#include <map>
#include <Vector3D.h>

#include "DynamicEntity.h"

typedef std::map<int, double>::iterator coeffs_iterator;

namespace coolpool
{
	// Simplest dynamic object of simulation, presented only by its position and mass.
	class PointMass: public DynamicEntity
	{
	public:

		virtual ~PointMass();

		// Overrides:
		virtual void onUpdate(double timeStep);

		// Cleans the non constant forces acting on the object.
		// It is called on the end of every frame.
		virtual void clear();

		virtual void reverse();

		// Saves the object status
		inline void savePointMass()
		{
			status_point_mass[0] = center_of_mass_location_.getX();
			status_point_mass[1] = center_of_mass_location_.getY();
			status_point_mass[2] = center_of_mass_location_.getZ();
			status_point_mass[3] = linear_momentum_.getX();
			status_point_mass[4] = linear_momentum_.getY();
			status_point_mass[5] = linear_momentum_.getZ();
			status_point_mass[6] = force_.getX();
			status_point_mass[7] = force_.getY();
			status_point_mass[8] = force_.getZ();
		}

		// Adds a force acting on the object during one step,
		// the force is reseted on the end of every frame.
		inline void addForce(const math_tools::Vector3D & force)
		{
			force_ += force;
		}

		// Getters:
		inline const math_tools::Vector3D & getCenterOfMassLocation() const
		{
			return center_of_mass_location_;
		}
		inline const math_tools::Vector3D & getLinearMomentum() const
		{
			return linear_momentum_;
		}
		inline const math_tools::Vector3D getLinearVelocity() const
		{
			return linear_momentum_ * (1 / mass_);
		}
		inline double getMass() const
		{
			return mass_;
		}
		inline math_tools::Vector3D getForce() const
		{
			return force_;
		}

		// Setters:
		inline void setCenterOfMassLocation(const math_tools::Vector3D & center_of_mass_location)
		{
			center_of_mass_location_ = center_of_mass_location;
		}
		inline void setLinearMomentum(const math_tools::Vector3D & linear_momentum)
		{
			linear_momentum_ = linear_momentum;
		}
		inline void setLinearVelocity(const math_tools::Vector3D & linear_velocity)
		{
			linear_momentum_ = linear_velocity * mass_;
		}
		inline void setMass(float mass)
		{
			mass_ = mass;
		}

	protected:

		PointMass(const PointMass & point_mass);
		PointMass();

	private:

		double mass_;

		// Position
		math_tools::Vector3D center_of_mass_location_;

		// Current linear momentum of the object
		math_tools::Vector3D linear_momentum_;

		// Cumulator of all the forces acting on the object during one step of simulation.
		math_tools::Vector3D force_;

		// Contains the status from previous frame.
		double status_point_mass[9];
	};
}
#endif
